/**
 * http连接类, 读取并解析http报文, 解析成功后构造handle类处理.
 * 依赖boost::asio, stream_server类新连接到来后调用operator()方法.
 * 
 * protocol: 流协议, 可使用tcp与ls(local stream)两种方式
 * handle: 解析完成后的处理类, 会构造一个此类并调用其operator(), 该类必须:
 *	1. 支持request和tcpsock两个类引用作为参数的构造函数
 *	2. 重载operator()操作符(无参), 供本类解析完协议后开始处理
 *   handle根据传入的tcpsock自行处理回复内容
 *   handle类如果需要异步处理, 应继承自boost::enable_shared_from_this, 否则operator()返回后即析构
 * 
 * 开发者   : Marco
 * 创建时间 : 2016年7月29日, 下午4:57
 */

#ifndef __MARCOPP_BST_CONNECTION_HTTP_HPP__
#define __MARCOPP_BST_CONNECTION_HTTP_HPP__


#include <boost/bind.hpp>
#include <boost/asio/read.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/asio/io_service.hpp>
#include <boost/asio/placeholders.hpp>
#include <boost/enable_shared_from_this.hpp>

#include <marcopp/http/request.h>

#include "stream_basic.h"

namespace marco {
namespace bst {

#define BUF_SIZ 4096

/**
 * http连接类
 */
template <typename protocol, typename handle> 
class connection_http : public boost::enable_shared_from_this<connection_http<protocol, handle> > {
public:
    connection_http(boost::asio::io_service& io_service) : socket_(io_service), buf(NULL), buf_size(BUF_SIZ) { }
    ~connection_http() { if (buf) free(buf); }
    
    /**
     * 开始处理入口, 新连接建立后, server类调用此函数, 本函数返回后, 如果引用计数未增加则自动析构.
     * 只有未读完, 还需读取的时候才会重新异步读取, 计数增加.
     */
    void operator()(void) {
//	out_log(log_lv_3, "Library new http connection, fd: %d.\n", socket_.native_handle());
	if (!(buf = (char*)malloc(BUF_SIZ))) return;
	
	socket_.async_read_some(boost::asio::buffer(buf, BUF_SIZ-1), 
		boost::bind(&connection_http<protocol, handle>::firstRecvHandle,
		this, boost::enable_shared_from_this<connection_http<protocol, handle> >::shared_from_this(), 
		boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
	// FIXME, 定时器,N秒没有回到则主动关闭,析构
    }
     
    /**
     * 获取socket, server类每次接收连接时需要传入tcp::socket对象, 对新连接的信息存储.
     * @return 
     */
    boost::asio::basic_stream_socket<protocol>& socket() {
	return socket_;
    }
    
private:
    /**
     * 首次接收
     * @param sptr 本对象智能指针
     * @param err 错误码
     * @param receivedBytes 接收字节数
     */
    void firstRecvHandle(boost::shared_ptr<connection_http<protocol, handle> > sptr,
	    const boost::system::error_code& err, int receivedBytes) {
	if (err) {
	    return;
	}

	parse(receivedBytes);
    }
    
    /**
     * 解析协议
     * @param len 数据长度
     */
    void parse(int len) {
	marco::http::parse_result ret;
	buf[len] = 0;
//	out_log(log_lv_4, "First Read %d bytes.\n%s\n", len, buf);
	
	if ((ret = request_.parse(buf, &len)) == marco::http::parse_success) {
//	    out_log(log_lv_3, "parse success.\n");
	    parse_complete();	// 调用虚函数, 解析完成, 由子类操作业务.
	
	} else if (ret == marco::http::parse_again) {
//	    out_log(log_lv_3, "parse again.\n");
	    start_read_again(len);
	}
    }
    
    /**
     * 异步开始再次读取, 只再读一次
     * @param buf 存储缓冲区
     * @param available_bytes 剩余读取的字节数
     */
    void start_read_again(int available_bytes) {
	if (available_bytes > BUF_SIZ-1) { // 剩余空间放不下.
	    buf_size = available_bytes+1;
	    if (!(buf = (char*)realloc(buf, buf_size)))	// 重新申请存储空间
		return;
	}
	
	// boost::asio::async_read可以保证能够读取到指定的字节数, 而socket_.async_receive则不保证.
	boost::asio::async_read(socket_, boost::asio::buffer(buf, available_bytes), 
		boost::bind(&connection_http<protocol, handle>::handle_read_again,
		this, boost::enable_shared_from_this<connection_http<protocol, handle> >::shared_from_this(),
		boost::asio::placeholders::error, boost::asio::placeholders::bytes_transferred));
    }
    
    /**
     * 再次收到数据处理
     * @param shared_pointer shared_ptr,不传则对象会被提前析构
     * @param ptr 空间 数据存储空间, 无论成功与否, 本函数需要释放
     * @param err 错误信息
     * @param bytes_transferred 读到的字节
     */
    void handle_read_again(boost::shared_ptr<connection_http<protocol, handle> > shared_pointer, 
				const boost::system::error_code& err, std::size_t bytes_transferred) {
	if (err) {  // 出现错误， 对方主动关闭之类
	    return;
	}
	
//	out_log(log_lv_4, "read %ld bytes again.\n", bytes_transferred);
	buf[bytes_transferred] = 0;
	request_.append_content_str(buf, bytes_transferred);
	parse_complete();
    }
    
    /**
     * 协议读取并解析完成, 构造处理类, 将socket传入, 由处理类决定回复内容
     */
    void parse_complete(void) {
	handle* h = new handle(request_, (tcpsock&)(connection_http<protocol, handle>::socket_));

	// 指定删除器, 并将自身shared_ptr传入, 否则本类会被提前析构, 要等handle类计数为0后, 调用了删除器deleter, 才能析构本类
	boost::shared_ptr<handle> ptr(h, boost::bind(&connection_http<protocol, handle>::deleter,
		this, h, connection_http<protocol, handle>::shared_from_this()));
	(*ptr)(buf, buf_size);
    }
    
    /**
     * API处理类指定的删除器, 当引用计数为0时调用, 删除原始指针
     * @param handle_ptr handle处理类指针, 由于没有使用shared_ptr默认删除器, 必须手动在此delete此原始指针
     * @param sptr 本类智能指针, 不传入的话会导致本类提前于handle类析构(handle有异步, 本类parse_over返回后计数就为0了)
     */
    void deleter(handle* handle_ptr, boost::shared_ptr<connection_http<protocol, handle> > sptr) {
	delete handle_ptr;	// 删除handle处理类
    }

    connection_http(const connection_http& orig); // 禁用拷贝构造
    connection_http& operator=(const connection_http& orig); // 禁用赋值

#if (__cplusplus >= 201103L)
    connection_http(connection_http&& orig) = delete; // 移动构造禁用
    connection_http& operator=(connection_http&& orig) = delete; // 移动赋值运算符重载禁用
#endif
    
    boost::asio::basic_stream_socket<protocol> socket_;
    marco::http::request request_;	    // 请求类
    char* buf;
    int buf_size;
};

} // namespace bst
} // namespace marco
#endif /* __MARCOPP_BST_CONNECTION_HTTP_HPP__ */